package carassius.DAL;

import carassius.BLL.Events.AquariumType.AquariumTypeAddedListener;
import carassius.BLL.Events.AquariumType.AquariumTypeAddedPublisher;
import carassius.BLL.Events.AquariumType.AquariumTypeRemovedListener;
import carassius.BLL.Events.AquariumType.AquariumTypeRemovedPublisher;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author siebz0r
 */
public class AquariumTypeTable
		extends Table<AquariumTypeRow, Integer>
		implements AquariumTypeAddedPublisher,
				   AquariumTypeRemovedPublisher
{
	//<editor-fold defaultstate="collapsed" desc="Fields">
	private final ArrayList<AquariumTypeAddedListener> _aquariumTypeAddedListeners;
	private final ArrayList<AquariumTypeRemovedListener> _aquariumTypeRemovedListeners;
	private final String SQL_ADD = "INSERT INTO aquarium_type VALUES (NULL, ?)",
			SQL_DELETE = "DELETE FROM aquarium_type WHERE id = ?",
			SQL_GET_ALL = "SELECT * FROM aquarium_type",
			SQL_GET_BY_ID = "SELECT * FROM aquarium_type WHERE id = ?";
	private boolean _allCached;
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Constructors">
	public AquariumTypeTable()
	{
		_aquariumTypeAddedListeners = new ArrayList<AquariumTypeAddedListener>();
		_aquariumTypeRemovedListeners = new ArrayList<AquariumTypeRemovedListener>();
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Methods">
	//<editor-fold defaultstate="collapsed" desc="SQL add">
	public AquariumTypeRow add(String name) throws SQLException
	{
		Integer id = add(new Object[]
				{
					name
				});
		if (id >= 0)
		{
			return getByPrimaryKey(id);
		}
		return null;
	}

	@Override
	public Integer add(Object[] args) throws SQLException
	{
		Integer out = -1;
		if (args != null
				&& args.length >= 1
				&& args[0] instanceof String
				&& !((String) args[0]).isEmpty())
		{
			PreparedStatement st = Database.prepareStatement(SQL_ADD);
			st.setObject(1, args[0], Types.VARCHAR);

			synchronized (getRows())
			{
				try
				{
					st.executeUpdate();
					ResultSet keys = st.getGeneratedKeys();

					if (keys.next())
					{
						out = keys.getInt(1);
						_allCached = false;
						AquariumTypeRow aquariumTypeRow = getByPrimaryKey(out);
						_allCached = true;
						fireAquariumTypeAddedEvent(aquariumTypeRow);
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return out;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="SQL delete">
	@Override
	public boolean delete(Integer id) throws SQLException
	{
		boolean result = false;
		if (id != null && id >= 0)
		{
			PreparedStatement st = Database.prepareStatement(SQL_DELETE);
			st.setInt(1, id);

			try
			{
				synchronized (getRows())
				{
					AquariumTypeRow aquariumTypeRow = getByPrimaryKey(id);
					if (st.executeUpdate() == 1)
					{
						result = true;
						getRows().remove(id);
						fireAquariumTypeRemovedEvent(aquariumTypeRow);
					}
				}
			}
			catch (SQLException ex)
			{
				throw ex;
			}
			finally
			{
				st.close();
			}
		}
		return result;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="SQL get">
	/**
	 * Gets all rows from the database.
	 * @return All the rows in an ArrayList
	 * @throws SQLException
	 */
	@Override
	public Collection<AquariumTypeRow> getAll() throws SQLException
	{
		PreparedStatement st = Database.prepareStatement(SQL_GET_ALL);

		synchronized (getRows())
		{
			if (!_allCached)
			{
				try
				{
					ResultSet query = st.executeQuery();

					while (query.next())
					{
						put(new AquariumTypeRow(query));
					}
					_allCached = true;
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
			return getRows().values();
		}
	}

	/**
	 * Get an AquariumTypeRow by it's ID.
	 * This method first tries to get the row from it's cache if it doesn't
	 * exist in it's cache, it gets the row from the database.
	 * @param id - the id to look for
	 * @return the row if found else null.
	 * @throws SQLException
	 */
	@Override
	public AquariumTypeRow getByPrimaryKey(Integer id) throws SQLException
	{
		AquariumTypeRow row = null;
		if (id != null && id >= 0)
		{
			synchronized (getRows())
			{
				row = getRows().get(id);
				if (row != null || _allCached)
				{
					return row;
				}

				PreparedStatement st = Database.prepareStatement(SQL_GET_BY_ID);
				st.setInt(1, id);

				try
				{
					ResultSet query = st.executeQuery();

					if (query.next())
					{
						row = new AquariumTypeRow(query);
						put(row);
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return row;
	}
	//</editor-fold>
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Events">
	//<editor-fold defaultstate="collapsed" desc="Added">
	@Override
	public void addAquariumTypeAddedEventListener(
			AquariumTypeAddedListener listener)
	{
		_aquariumTypeAddedListeners.add(listener);
	}

	@Override
	public void removeAquariumTypeAddedEventListener(
			AquariumTypeAddedListener listener)
	{
		_aquariumTypeAddedListeners.remove(listener);
	}

	private void fireAquariumTypeAddedEvent(AquariumTypeRow row)
	{
		for (AquariumTypeAddedListener listener : _aquariumTypeAddedListeners)
		{
			listener.aquariumTypeAdded(row);
		}
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Removed">
	@Override
	public void addAquariumTypeRemovedEventListener(
			AquariumTypeRemovedListener listener)
	{
		_aquariumTypeRemovedListeners.add(listener);
	}

	@Override
	public void removeAquariumTypeRemovedEventListener(
			AquariumTypeRemovedListener listener)
	{
		_aquariumTypeRemovedListeners.remove(listener);
	}

	private void fireAquariumTypeRemovedEvent(AquariumTypeRow row)
	{
		for (AquariumTypeRemovedListener listener : _aquariumTypeRemovedListeners)
		{
			listener.aquariumTypeRemoved(row);
		}
	}
	//</editor-fold>
	//</editor-fold>
}